package com.shy.pointcut;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Aspect
@Component
public class LogAspect {

    @Pointcut("execution(* com.shy.pointcut.UserService.*(..) )")
    public void myPointCut() {
    }

    // 类级别 com.shy.advice.DataBaseService类中所有方法
    @Pointcut("within(com.shy.pointcut.DataBaseService)")
    public void myPointCutWithIn() {
    }

    // 所有Log注解都会被匹配
    // 如果要在通知的参数中绑定注解就不能单独抽取
    @Pointcut("@annotation(Log)")
    public void annotationPointCut() {}
    // 切面方法 计时
    @Around("execution(public void com.shy.pointcut.UserService.*(..) )")
    public void log(ProceedingJoinPoint proceePoint) {
        long begin = System.currentTimeMillis();

        try {
            proceePoint.proceed();
        } catch (Throwable e) {
            System.out.println("异常信息：" + e.getMessage());
        }

        long end = System.currentTimeMillis();

        System.out.println("耗时：" + (end - begin) + "毫秒");

    }

    //如果要在通知的参数中绑定注解，声明的就是参数名，不能是注解类型 例如下面的log
    @Before("myPointCut() && @annotation(log)")
    public void logBefore(JoinPoint joinPoint, Log log) {
        String name = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        Object target = joinPoint.getTarget();
        System.out.println("---->" + log.value());
        System.out.println("前置通知 方法名：" + target.getClass().getName() + "." + name + " 参数为： " + Arrays.toString(args));
    }

    @After("myPointCut()")
    public void logAfter(JoinPoint joinPoint) {
        String name = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        Object target = joinPoint.getTarget();

        System.out.println("后置通知，方法名：" + target.getClass().getName() + "." + name + " 参数为： " + Arrays.toString(args));
    }

    @AfterReturning(value = "myPointCut()", returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) {
        String name = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        Object target = joinPoint.getTarget();

        System.out.println("返回通知 方法名：" + target.getClass().getName() + "." + name + " 参数为： " + Arrays.toString(args) + " 返回值为：" + result);
    }

    @AfterThrowing(value = "myPointCut()", throwing = "e")
    public void logAfterThrowing(JoinPoint joinPoint, Exception e) {
        String name = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        Object target = joinPoint.getTarget();

        System.out.println("方法名：" + target.getClass().getName() + "." + name + " 参数为： " + Arrays.toString(args) + " 异常信息：" + e.getMessage());
    }

    @Before("myPointCutWithIn()")
    public void logWithInAdd(JoinPoint joinPoint) {
        String name = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        Object target = joinPoint.getTarget();

        System.out.println("database 前置通知 方法名：" + target.getClass().getName() + "." + name + " 参数为： " + Arrays.toString(args));
    }
}
